#include "server.h"
#include <string>
#include "common.h"
#include "JsApp.h"
#include "MouseInput.h"
#include "input_device_manager.h"

std::string successMsg = "{ \"section\":\"engine\", \"action\":\"launch\", \"status\":\"success\" }";
std::string failMsg = "{ \"section\":\"engine\", \"action\":\"launch\", \"status\":\"fail\" }";

void on_run(server* s, unsigned int port) {
    try {
        // Set logging settings
        //s->set_access_channels(websocketpp::log::alevel::disconnect);
        //s->set_error_channels(websocketpp::log::elevel::fatal);
        s->clear_access_channels(websocketpp::log::alevel::all);
        s->clear_error_channels(websocketpp::log::elevel::all);

        // Register our message handler
        s->set_message_handler(bind(&on_message, s, ::_1, ::_2));
        s->set_http_handler(bind(&on_http, s, ::_1));
        s->set_fail_handler(bind(&on_fail, s, ::_1));
        s->set_open_handler(bind(&on_open, s, ::_1));
        s->set_close_handler(bind(&on_close, ::_1));
        s->set_validate_handler(bind(&validate, s, ::_1));

        // Initialize ASIO
        s->init_asio();
        s->set_reuse_addr(true);

        // Listen on port
        s->listen(port);
        std::cout <<"[INFO]:listen on " << port << std::endl;
        // Start the server accept loop
        s->start_accept();
        // Start the ASIO io_service run loop
        s->run();
        
    }
    catch (websocketpp::exception const& e) {
        std::cout << e.what() << std::endl;
    }
    catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    catch (...) {
        std::cout << "other exception" << std::endl;
    }
}

void on_stop(server* s)
{
    try {
         s->stop();
    } catch (websocketpp::exception const& e) {
        std::cout << e.what() << std::endl;
    }
    catch (const std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    catch (...) {
        std::cout << "other exception" << std::endl;
    }

}

bool validate(server*, websocketpp::connection_hdl) {
    return true;
}

void on_http(server* s, websocketpp::connection_hdl hdl) {
    try {
        server::connection_ptr con = s->get_con_from_hdl(hdl);
        websocketpp::http::parser::request rt = con->get_request();
        const std::string& strUri = rt.get_uri();
        const std::string& strMethod = rt.get_method();

        /*
         *  const std::string& strBody = rt.get_body();     //只针对post时有数据
         *  const std::string& strHost = rt.get_header("host");
         *  const std::string& strVersion = rt.get_version();
         *  std::cout<<"Received one "<< strMethod.c_str()
         *           << "request:" << strUri.c_str()
         *           << "  thread ID="<< std::this_thread::get_id()
         *           << "  host = " << strHost
         *           << std::endl;
         */


        //得到exe所在的路径
        const std::string g_strPath = ApplicationPath() + "/www" + strUri;
        int code = websocketpp::http::status_code::ok;
        std::string strBuffer;

        if (strMethod.compare("POST") == 0) {
            //对于post提交的，直接跳转到深鸿会 Gitee
            con->set_status(websocketpp::http::status_code::value(websocketpp::http::status_code::found));
            con->append_header("location", "https://gitee.com/hiharmonica/harmonica-previewer");
        }
        else if (strMethod.compare("GET") == 0) {
            if (strUri.compare("/") == 0 || strUri.compare("/index.html") == 0) {
                //请求主页 读取主页页面文件内容然后返回给浏览器
                if (ReadFileContent((ApplicationPath() + "/www/index.html").c_str(), std::ios_base::in, strBuffer)){
                    con->set_body(strBuffer);
                }
                else {
                    //页面不存在，返回404
                    code = websocketpp::http::status_code::not_found;
                }
                //HTTP返回码
                con->set_status(websocketpp::http::status_code::value(code));
            }
            else if (strUri.compare("/favicon.ico") == 0) {
                //请求网站图标，读取图标文件，直接返回二进制数据
                if (ReadFileContent(g_strPath.c_str(), std::ios_base::binary, strBuffer)) {
                    con->set_body(strBuffer);
                }else {
                    //页面不存在，返回404
                    code = websocketpp::http::status_code::not_found;
                }
                //HTTP返回码 OK
                con->set_status(websocketpp::http::status_code::value(code));
            }
            else if (strUri.compare("/port") == 0) {
                //请求websocket端口
                con->set_body(std::to_string(port));
                //HTTP返回码 OK
                con->set_status(websocketpp::http::status_code::value(code));
            }
            else if (strUri.find(".jpg") != std::string::npos || strUri.find(".png") != std::string::npos) {
                if (ReadFileContent(g_strPath.c_str(), std::ios_base::binary, strBuffer)) {
                    con->set_body(strBuffer);
                }
                else {
                    //页面不存在，返回404
                    code = websocketpp::http::status_code::not_found;
                }
                //HTTP返回码
                con->set_status(websocketpp::http::status_code::value(code));
            }
            else {
                if (ReadFileContent(g_strPath.c_str(), std::ios_base::in, strBuffer)) {
                    con->set_body(strBuffer);
                }
                else {
                    //页面不存在，返回404
                    code = websocketpp::http::status_code::not_found;
                }
                con->set_status(websocketpp::http::status_code::value(code));//HTTP返回码
            }
        }

        strBuffer.clear();
    }
    catch (websocketpp::exception const &e) {
        std::cout << "exception: " << e.what() << std::endl;
    }
    catch(std::exception &e) {
        std::cout << "exception: " << e.what() << std::endl;
    }
    catch(...) {
        std::cout << "other exception" << std::endl;
    }
}

void on_fail(server* s, websocketpp::connection_hdl hdl) {
    server::connection_ptr con = s->get_con_from_hdl(hdl);
    std::cout << "Fail handler: " << con->get_ec() << " " << con->get_ec().message() << std::endl;
}

void on_open(server* s, websocketpp::connection_hdl hdl) {
    //申请websocket upgrade成功之后，调用open_handler函数，回调on_open。
    //在这里，可以获取http请求的地址、参数信息。
    server::connection_ptr con = s->get_con_from_hdl(hdl);
    //std::cout << "Open handler" << con->get_ec() << " " << con->get_ec().message() << std::endl;
    websocketpp::config::core::request_type requestClient = con->get_request();
    std::string strMethod = requestClient.get_method();		//请求方法
    std::string strUri = requestClient.get_uri();			//请求uri地址，可以解析参数
    std::string strRequestOperateCommand = "";				//操作类型
    if(strUri.compare("/plugin") == 0) {

    }else {
        PMessage pMessage;
        pMessage.name = "Previewer";
        pMessage.command = "screeninfo";
        pMessage.args["width"] = protocalMsg.devices[0].screen.width;
        pMessage.args["height"] = protocalMsg.devices[0].screen.height;
        sendMsg(s, hdl, pMessage.toString(), websocketpp::frame::opcode::value::TEXT);
        web_hdl = hdl;
        m_send = true;
        isChanged = true;
    }
}

void on_close(websocketpp::connection_hdl hdl) {
    if(web_hdl.lock() == hdl.lock()) {
        m_send = false;
        isChanged = true;
        web_hdl.reset();
    }
    std::cout << "Close handler" << hdl.lock().get() << std::endl;
}

// Define a callback to handle incoming messages
void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) {
    /*
        hdl.lock().get() 获得连接标识
        msg->get_payload() 是收到的消息内容
        msg->get_opcode() 是收到消息的类型 ，包含：文本TEXT,二进制BINARY等等

        std::cout << "on_message called with hdl: " << hdl.lock().get()
                  << " and message: " << msg->get_payload()
                  << std::endl;
    */

    std::string msgBody = msg->get_payload();
    if(msgBody.find("plugin") != std::string::npos) {
        CMessage cMessage = CMessage::parseJson(msgBody);
        if(cMessage.command  == "restart") {
            // restart engine
            std::cout << "[INFO]:restart engine" << std::endl;
            m_send = false;
            try {
                JsApp::GetInstance().Stop();
                if(access(cMessage.args["jsBundle"].c_str(),0) == -1) {
                    std::cout << "[Error]:jsBundle path does not exist!" << std::endl;
                    sendMsg(s, hdl, failMsg, msg->get_opcode());
                    on_stop(s);
                }
                JsApp::GetInstance().SetJsAppPath(cMessage.args["jsBundle"]);
                if(JsApp::GetInstance().Start() == false) {
                    std::cout << "[Error]:App start err!" << std::endl;
                    sendMsg(s, hdl, failMsg, msg->get_opcode());
                    on_stop(s);
                }
            } catch (const std::exception& e) {
                std::cout << e.what() << std::endl;
            }
            m_send = true;
            isChanged = true;
            sendMsg(s, hdl, successMsg, msg->get_opcode());
        }else if (cMessage.command  == "exit") {
            //std::cout << "exit preview" << std::endl;
            m_send = false;
            JsApp::GetInstance().Stop();
            sendMsg(s, hdl, successMsg, msg->get_opcode());
            on_stop(s);
        }else if (cMessage.command  == "theme") {
            std::cout << "[INFO]:change theme" << std::endl;
            sendMsg(s, hdl, successMsg, msg->get_opcode());
        }
    }else if(msgBody.find("version") != std::string::npos) {
        PMessage pMessage = PMessage::parseJson(msgBody);
        if(pMessage.command  == "MousePress") {
            MouseInput::GetInstance().SetMousePosition(pMessage.args["x"],pMessage.args["y"]);
            MouseInput::GetInstance().SetMouseStatus(MouseInput::MouseStatus::INDEV_STATE_PRESS);
            OHOS::InputDeviceManager::GetInstance()->Callback();
        }else if (pMessage.command  == "MouseMove") {
            MouseInput::GetInstance().SetMousePosition(pMessage.args["x"],pMessage.args["y"]);
            MouseInput::GetInstance().SetMouseStatus(MouseInput::MouseStatus::INDEV_STATE_PRESS);
            OHOS::InputDeviceManager::GetInstance()->Callback();
        }else if (pMessage.command  == "MouseRelease") {
            MouseInput::GetInstance().SetMousePosition(pMessage.args["x"],pMessage.args["y"]);
            MouseInput::GetInstance().SetMouseStatus(MouseInput::MouseStatus::INDEV_STATE_RELEASE);
            OHOS::InputDeviceManager::GetInstance()->Callback();
        }
    }else {
        sendMsg(s, hdl, msg->get_payload(), msg->get_opcode());
    }
}

/*
    发送消息
    s->send(
    hdl, //连接
    msg, //消息
    opCode;//消息类型
*/
void sendMsg(server* s,
            websocketpp::connection_hdl hdl,
            std::string msg,
            websocketpp::frame::opcode::value opCode){
    try {
        s->send(hdl, msg, opCode);
    }
    catch (websocketpp::exception const& e) {
        std::cout << "Echo failed because: "
                  << "(" << e.what() << ")" << std::endl;
    }
}

/*
    发送图片
    s->send(
    hdl, //连接
    payload, //图片数组
    len, //数组长度
    opCode;//消息类型
*/

void sendImg(server* s,websocketpp::connection_hdl hdl, void const * payload, size_t len, websocketpp::frame::opcode::value op){
    try {
        s->send(hdl, payload, len, op);
    }
    catch (websocketpp::exception const& e) {
        std::cout << "Echo failed because: "
                  << "(" << e.what() << ")" << std::endl;
    }
}
